﻿
#pragma once

#ifndef WRAPPER_SIZE
    #define WRAPPER_SIZE sizeof(size_t)*4
#endif

#ifndef WRAPPER_ITERATOR_SIZE
    #define WRAPPER_ITERATOR_SIZE sizeof(size_t)*4
#endif

#include "types.h"
#include <limits>

namespace tools{
    namespace wrapper_details{

    //-----------------------------------------------------------------------------------------
        template<class T> struct WrapperSizeStrategy                { enum { eSIZE = sizeof(T)    , eITERATOR_SIZE = WRAPPER_ITERATOR_SIZE }; };
        template<> struct WrapperSizeStrategy<ONLY_REGISTRED_TYPES> { enum { eSIZE = WRAPPER_SIZE , eITERATOR_SIZE = WRAPPER_ITERATOR_SIZE }; };
        template<> struct WrapperSizeStrategy<void>                 { enum { eSIZE = WRAPPER_SIZE , eITERATOR_SIZE = WRAPPER_ITERATOR_SIZE }; };
    //-----------------------------------------------------------------------------------------
        template<class T> struct PropertyType
        {
            enum { eIS_INTEGER = ::std::numeric_limits<T>::is_integer                   };
            enum { eIS_FLOAT   = ::std::is_floating_point<T>::value                     };
            enum { eIS_BOOL    = ::std::is_same<T,bool>::value                          };
            enum { eIS_INT     = eIS_INTEGER && !eIS_BOOL                               };
            enum { eIS_STRICT  = !eIS_FLOAT && !eIS_INT && Type2Enum<T>::eTYPE!=eNULL   };
            enum { eIS_OTHER   = !eIS_FLOAT && !eIS_INT && !eIS_STRICT                  };
            enum { eIS_SIGNED  = ::std::is_signed<T>::value                             };
            enum { eSIGNED_INTEGER   = eIS_INT && eIS_SIGNED                            };
            enum { eUNSIGNED_INTEGER = eIS_INT && !eIS_SIGNED                           };
        };
    //-----------------------------------------------------------------------------------------

        template<class T> struct HasIteratorBegin
        {
            typedef char (&No)[1]; typedef char (&Yes)[2];
            template<class U>static Yes HelpMe( decltype(std::declval<U>().begin())* p);
            template<class U>static No HelpMe(...);
            enum { value = sizeof(HelpMe<T>(0)) == sizeof(Yes) };
        };
        template<class T> struct HasIteratorEnd
        {
            typedef char (&No)[1]; typedef char (&Yes)[2];
            template<class U>static Yes HelpMe( decltype(std::declval<U>().end())* p);
            template<class U>static No HelpMe(...);
            enum { value = sizeof(HelpMe<T>(0)) == sizeof(Yes) };
        };

        template<class T> struct PropertyContainer
        {
            enum { eHAS_BEGIN  = HasIteratorBegin<T>::value                    };
            enum { eHAS_END    = HasIteratorEnd<T>::value                      };
            enum { eHAS_CBEGIN = HasIteratorBegin<const T>::value              };
            enum { eHAS_CEND   = HasIteratorEnd<const T>::value                };
            enum { eVALID = eHAS_BEGIN && eHAS_END && eHAS_CBEGIN && eHAS_CEND };
        };

        template<class T, int IS_CONTAINER = PropertyContainer<T>::eVALID > struct PropertyIterator
        {
            enum { eSIZE_BEGIN  = sizeof( ::std::declval<T>().begin()       )  };
            enum { eSIZE_CBEGIN = sizeof( ::std::declval<const T>().begin() )  };
            enum { eSIZE_END    = sizeof( ::std::declval<T>().end()         )  };
            enum { eSIZE_CEND   = sizeof( ::std::declval<const T>().end()   )  };
        private:            
            enum { ebeg = eSIZE_BEGIN > eSIZE_CBEGIN ? eSIZE_BEGIN: eSIZE_CBEGIN };
            enum { eend = eSIZE_END > eSIZE_CEND ? eSIZE_END: eSIZE_CEND };
        public:
            enum { eSIZE =  ebeg > eend ? ebeg : eend };
            enum { eVALID = 1 };

            typedef decltype( ::std::declval<T>().begin() )       Iterator;
            typedef decltype( ::std::declval<const T>().begin() ) ConstIterator;
            typedef decltype( *(::std::declval<Iterator>()) )     TypeValue;
        };
        template<class T> struct PropertyIterator<T,false>
        {
            enum { eSIZE_BEGIN  = 0 };
            enum { eSIZE_CBEGIN = 0 };
            enum { eSIZE_END    = 0 };
            enum { eSIZE_CEND   = 0 };
            enum { eSIZE        = 0 };
            enum { eVALID       = 0 };
        };

    //-----------------------------------------------------------------------------------------
       

    }//namespace wrapper_details
}//namespace tools

